package org.maylove.wuziqi.ws;

import jakarta.websocket.*;
import jakarta.websocket.server.ServerEndpoint;
import org.maylove.wuziqi.common.CustomEvent;
import org.maylove.wuziqi.common.EventMessage;
import org.maylove.wuziqi.common.RedisUtil;
import org.maylove.wuziqi.pojo.game.dto.GameNoGameDto;
import org.maylove.wuziqi.pojo.game.dto.GameNoStartDto;
import org.maylove.wuziqi.pojo.game.dto.GameRoomDto;
import org.maylove.wuziqi.pojo.game.dto.GameRoomPlayerDto;
import org.maylove.wuziqi.service.GameService;
import org.maylove.wuziqi.service.HistoryService;
import org.maylove.wuziqi.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@Component
@ServerEndpoint(value = "/game")
public class GameEndPoint {

    private static final Map<Long, Session> sessions = new HashMap<>();
    private static final Map<Session, Long> userId = new HashMap<>();

    private static RedisUtil redisUtil;

    private static GameService gameService;

    private static UserService userService;

    private static HistoryService historyService;

    Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    public void setRedisUtil(RedisUtil redisUtil) {
        GameEndPoint.redisUtil = redisUtil;
    }

    @Autowired
    public void setGameService(GameService gameService) {
        GameEndPoint.gameService = gameService;
    }

    @Autowired
    public void setUserService(UserService userService) {
        GameEndPoint.userService = userService;
    }

    @Autowired
    public void setHistoryService(HistoryService historyService) {
        GameEndPoint.historyService = historyService;
    }

    @OnClose
    public void onClose(Session session) {
        if(userId.containsKey(session)) {
            sessions.remove(userId.get(session));
            userId.remove(session);
        }
    }

    @OnMessage
    public void onMessage(Session session, String message) {
        if(message.startsWith("get_")) {
    //  获取房间信息
            String token = message.substring("get_".length());

            //  检查用户是否处于登录态
            if(token.isEmpty() || !redisUtil.exists(token + "_userId") || redisUtil.get(token + "_userId") == null || !redisUtil.get(redisUtil.get(token + "_userId").toString()).equals(token)) {
                sendOneMsg(session, "User not logged in!");
                return;
            }

            //  检查用户是否在房间内
            if(!redisUtil.exists(token + "_roomId") || redisUtil.get(token + "_roomId") == null) {
                sendOneMsg(session, "The user is not in the room!");
                return;
            }

            sessions.put((Long)redisUtil.get(token + "_userId"), session);
            userId.put(session, (Long)redisUtil.get(token + "_userId"));

            GameRoomDto gameRoomDto = gameService.get((Long)redisUtil.get(token + "_userId"), (Integer)redisUtil.get(token + "_roomId"));
            if(gameRoomDto == null) sendOneMsg(session, "The user is not in the room!");
            else {
                if(redisUtil.get(token + "_userId").equals(gameRoomDto.getPlayer2())) {
                    sendOneMsg(gameRoomDto.getPlayer1(), gameRoomDto.toString());
                }
                sendOneMsg(session, gameRoomDto.toString());
            }
        }
        else if(message.startsWith("getNickname_")) {
    //  获取昵称
            String user = message.substring("getNickname_1".length());
            Long userId = Long.parseLong(user);
            if(message.startsWith("getNickname_1")) {
                sendOneMsg(session, "returnNickname_1_" + userService.getSimpleUser(userId).toString());
            }
            else {
                sendOneMsg(session, "returnNickname_2_" + userService.getSimpleUser(userId).toString());
            }
        }
        else if(message.startsWith("prepare_")) {
    //  准备游戏
            String token = message.substring("prepare_".length());

            //  检查用户是否处于登录态
            if(token.isEmpty() || !redisUtil.exists(token + "_userId") || redisUtil.get(token + "_userId") == null || !redisUtil.get(redisUtil.get(token + "_userId").toString()).equals(token)) {
                sendOneMsg(session, "User not logged in!");
                return;
            }

            //  检查用户是否在房间内
            if(!redisUtil.exists(token + "_roomId") || redisUtil.get(token + "_roomId") == null) {
                sendOneMsg(session, "The user is not in the room!");
                return;
            }

            String success = gameService.prepare((Integer)redisUtil.get(token + "_roomId"), (Long)redisUtil.get(token + "_userId"));
            if(success.equals("success")) {
                GameRoomPlayerDto dto = gameService.get((Integer)redisUtil.get(token + "_roomId"));
                if(dto.getPlayer1().equals((Long)redisUtil.get(token + "_userId"))) {
                    sendOneMsg(dto.getPlayer1(), "Player One Preparation!");
                    if(dto.getPlayer2() != null) {
                        sendOneMsg(dto.getPlayer2(), "Player One Preparation!");
                    }
                }
                else {
                    sendOneMsg(dto.getPlayer1(), "Player Two Preparation!");
                    sendOneMsg(dto.getPlayer2(), "Player Two Preparation!");
                }
            }
            else sendOneMsg(session, success);
        }
        else if(message.startsWith("game_")) {
    //  落子
            String token = message.substring("game_0101".length());
            Integer x = Integer.parseInt(message.substring("game_".length(),"game_01".length()));
            Integer y = Integer.parseInt(message.substring("game_01".length(),"game_0101".length()));

            //  检查用户是否处于登录态
            if(token.isEmpty() || !redisUtil.exists(token + "_userId") || redisUtil.get(token + "_userId") == null || !redisUtil.get(redisUtil.get(token + "_userId").toString()).equals(token)) {
                sendOneMsg(session, "User not logged in!");
                return;
            }

            //  检查用户是否在房间内
            if(!redisUtil.exists(token + "_roomId") || redisUtil.get(token + "_roomId") == null) {
                sendOneMsg(session, "The user is not in the room!");
                return;
            }

            String success = gameService.game((Long)redisUtil.get(token + "_userId"), (Integer)redisUtil.get(token + "_roomId"), x, y);
            if(success.equals("success")) {
                GameRoomPlayerDto dto = gameService.get((Integer)redisUtil.get(token + "_roomId"));
                sendOneMsg(dto.getPlayer1(), String.format("%02d", x) + String.format("%02d", y));
                sendOneMsg(dto.getPlayer2(), String.format("%02d", x) + String.format("%02d", y));
            }
            else if(success.equals("win")) {
                GameRoomPlayerDto dto = gameService.get((Integer)redisUtil.get(token + "_roomId"));
                Integer[][] boards = gameService.getBoard((Integer)redisUtil.get(token + "_roomId"));
                sendOneMsg(dto.getPlayer1(), "gameover" + String.format("%02d", x) + String.format("%02d", y));
                sendOneMsg(dto.getPlayer2(), "gameover" + String.format("%02d", x) + String.format("%02d", y));
                if(dto.getPlayer1().equals((Long)redisUtil.get(token + "_userId"))) {
                    userService.win(dto.getPlayer1());
                    userService.fail(dto.getPlayer2());
                    historyService.addHistory(dto.getPlayer1(), 1, 0, boards);
                    historyService.addHistory(dto.getPlayer2(), 0, 0, boards);
                    sendOneMsg(dto.getPlayer1(), "Win!");
                    sendOneMsg(dto.getPlayer2(), "Fail!");
                }
                else {
                    userService.win(dto.getPlayer2());
                    userService.fail(dto.getPlayer1());
                    historyService.addHistory(dto.getPlayer1(), 0, 0, boards);
                    historyService.addHistory(dto.getPlayer2(), 1, 0, boards);
                    sendOneMsg(dto.getPlayer2(), "Win!");
                    sendOneMsg(dto.getPlayer1(), "Fail!");
                }
                gameService.cleanRoom((Integer)redisUtil.get(token + "_roomId"));
            }
            else sendOneMsg(session, success);
        }
        else if(message.startsWith("back_")) {
    //  悔棋
            String token = message.substring("back_".length());

            //  检查用户是否处于登录态
            if(token.isEmpty() || !redisUtil.exists(token + "_userId") || redisUtil.get(token + "_userId") == null || !redisUtil.get(redisUtil.get(token + "_userId").toString()).equals(token)) {
                sendOneMsg(session, "User not logged in!");
                return;
            }

            //  检查用户是否在房间内
            if(!redisUtil.exists(token + "_roomId") || redisUtil.get(token + "_roomId") == null) {
                sendOneMsg(session, "The user is not in the room!");
                return;
            }

            String success = gameService.back((Long)redisUtil.get(token + "_userId"), (Integer)redisUtil.get(token + "_roomId"));
            if(success.startsWith("back")) {
                GameRoomPlayerDto dto = gameService.get((Integer)redisUtil.get(token + "_roomId"));
                sendOneMsg(dto.getPlayer1(), success);
                sendOneMsg(dto.getPlayer2(), success);
            }
            else sendOneMsg(session, success);
        }
        else if(message.startsWith("giveUp_")) {
    //  认输
            String token = message.substring("giveUp_".length());
            //  检查用户是否处于登录态
            if(token.isEmpty() || !redisUtil.exists(token + "_userId") || redisUtil.get(token + "_userId") == null || !redisUtil.get(redisUtil.get(token + "_userId").toString()).equals(token)) {
                sendOneMsg(session, "User not logged in!");
                return;
            }

            //  检查用户是否在房间内
            if(!redisUtil.exists(token + "_roomId") || redisUtil.get(token + "_roomId") == null) {
                sendOneMsg(session, "The user is not in the room!");
                return;
            }

            String success = gameService.giveUp((Long)redisUtil.get(token + "_userId"), (Integer)redisUtil.get(token + "_roomId"));
            if(success.equals("success")) {
                Integer[][] boards = gameService.getBoard((Integer)redisUtil.get(token + "_roomId"));
                GameRoomPlayerDto dto = gameService.get((Integer)redisUtil.get(token + "_roomId"));
                if(dto.getPlayer1().equals((Long)redisUtil.get(token + "_userId"))) {
                    userService.win(dto.getPlayer2());
                    userService.fail(dto.getPlayer1());
                    historyService.addHistory(dto.getPlayer1(), 0, 1, boards);
                    historyService.addHistory(dto.getPlayer2(), 1, 1, boards);
                    sendOneMsg(dto.getPlayer1(), "Fail!");
                    sendOneMsg(dto.getPlayer2(), "Win!");
                }
                else {
                    userService.win(dto.getPlayer1());
                    userService.fail(dto.getPlayer2());
                    historyService.addHistory(dto.getPlayer1(), 1, 1, boards);
                    historyService.addHistory(dto.getPlayer2(), 0, 1, boards);
                    sendOneMsg(dto.getPlayer2(), "Fail!");
                    sendOneMsg(dto.getPlayer1(), "Win!");
                }
                gameService.cleanRoom((Integer)redisUtil.get(token + "_roomId"));
            }
            else sendOneMsg(session, success);
        }
        else if(message.startsWith("exit_")) {
    //  退出房间
            String token = message.substring("exit_".length());
            //  检查用户是否处于登录态
            if(token.isEmpty() || !redisUtil.exists(token + "_userId") || redisUtil.get(token + "_userId") == null || !redisUtil.get(redisUtil.get(token + "_userId").toString()).equals(token)) {
                sendOneMsg(session, "User not logged in!");
                return;
            }

            //  检查用户是否在房间内
            if(!redisUtil.exists(token + "_roomId") || redisUtil.get(token + "_roomId") == null) {
                sendOneMsg(session, "The user is not in the room!");
                return;
            }

            String success = gameService.exit((Long)redisUtil.get(token + "_userId"), (Integer)redisUtil.get(token + "_roomId"));
            if(success.startsWith("success")) {
                GameRoomPlayerDto dto  = gameService.get((Integer)redisUtil.get(token + "_roomId"));
                if(success.equals("success1")) {
                    sendOneMsg(dto.getPlayer1(), "success!");
                    if(dto.getPlayer2() != null) {
                        sendOneMsg(dto.getPlayer2(), "The homeowner dissolved the room!");
                        redisUtil.delete((String) redisUtil.get(dto.getPlayer2().toString()) + "_roomId");
                    }
                    gameService.free((Integer)redisUtil.get(token + "_roomId"));
                }
                else {
                    sendOneMsg(dto.getPlayer2(), "success!");
                    sendOneMsg(dto.getPlayer1(), "The player has launched a room!");
                }
                redisUtil.delete(token + "_roomId");
            }
            else sendOneMsg(session, success);
        }
        else if(message.startsWith("trans_")) {
    //  转移房主
            String token = message.substring("trans_".length());
            //  检查用户是否处于登录态
            if(token.isEmpty() || !redisUtil.exists(token + "_userId") || redisUtil.get(token + "_userId") == null || !redisUtil.get(redisUtil.get(token + "_userId").toString()).equals(token)) {
                sendOneMsg(session, "User not logged in!");
                return;
            }

            //  检查用户是否在房间内
            if(!redisUtil.exists(token + "_roomId") || redisUtil.get(token + "_roomId") == null) {
                sendOneMsg(session, "The user is not in the room!");
                return;
            }

            String success = gameService.trans((Long)redisUtil.get(token + "_userId"), (Integer)redisUtil.get(token + "_roomId"));
            if(success.equals("success")) {
                GameRoomPlayerDto dto  = gameService.get((Integer)redisUtil.get(token + "_roomId"));
                sendOneMsg(dto.getPlayer1(), "You have become the homeowner!");
                sendOneMsg(dto.getPlayer2(), "You are no longer the homeowner!");
            }
            else sendOneMsg(session, success);
        }
        logger.info("getmsg:{}", message);
    }

    //  单点发送消息
    private void sendOneMsg(Long userId, String msg) {
        if(sessions.containsKey(userId)) {
            Session session = sessions.get(userId);
            if(session.isOpen()) {
                synchronized (session) {
                    session.getAsyncRemote().sendText(msg);
                }
            }
            logger.info("sendOneMsg:{} to {}", msg, userId);
        }
    }
    private void sendOneMsg(Session session, String msg) {
        if(session.isOpen()) {
            synchronized (session) {
                session.getAsyncRemote().sendText(msg);
            }
        }
        logger.info("sendOneMsg:{}", msg);
    }


    //  监听是否存在长时间不准备的
    @EventListener
    private void test(CustomEvent event) {
        EventMessage eventMessage = event.getEventMessage();
        if(eventMessage.getMsg().equals("Players in the room do not start playing for a long time!")) {
            Integer roomId = ((GameNoStartDto)eventMessage.getData()).getRoomId();
            GameRoomPlayerDto dto = gameService.get(roomId);
            if(dto.getPlayer1() != null) {
                if(redisUtil.exists(dto.getPlayer1().toString())) {
                    if(redisUtil.exists((String) redisUtil.get(dto.getPlayer1().toString()) + "_roomId")) {
                        if(redisUtil.get((String) redisUtil.get(dto.getPlayer1().toString())+ "_roomId") == roomId)  {
                            redisUtil.delete((String) redisUtil.get(dto.getPlayer1().toString()) + "_roomId");
                            sendOneMsg(dto.getPlayer1(), "Long time no game started, room closed!");
                        }
                    }
                }
            }
            if(dto.getPlayer2() != null) {
                if(redisUtil.exists(dto.getPlayer2().toString())) {
                    if(redisUtil.exists((String) redisUtil.get(dto.getPlayer2().toString()) + "_roomId")) {
                        if(redisUtil.get((String) redisUtil.get(dto.getPlayer2().toString()) + "_roomId") == roomId)  {
                            redisUtil.delete((String) redisUtil.get(dto.getPlayer2().toString()) + "_roomId");
                            sendOneMsg(dto.getPlayer2(), "Long time no game started, room closed!");
                        }
                    }
                }
            }
            gameService.free(roomId);
            logger.info("Room id:{} long time no start", roomId);
        }
        else if(eventMessage.getMsg().equals("Players do not play for a long time!")) {
            gameService.giveUp(((GameNoGameDto)eventMessage.getData()).getUserId(), ((GameNoGameDto)eventMessage.getData()).getRoomId());
            Integer[][] boards = gameService.getBoard(((GameNoGameDto)eventMessage.getData()).getRoomId());
            GameRoomPlayerDto dto = gameService.get(((GameNoGameDto)eventMessage.getData()).getRoomId());
            if(dto.getPlayer1().equals(((GameNoGameDto)eventMessage.getData()).getUserId())) {
                userService.win(dto.getPlayer2());
                userService.fail(dto.getPlayer1());
                historyService.addHistory(dto.getPlayer1(), 0, 1, boards);
                historyService.addHistory(dto.getPlayer2(), 1, 1, boards);
                sendOneMsg(dto.getPlayer1(), "Fail!");
                sendOneMsg(dto.getPlayer2(), "Win!");
            }
            else {
                userService.win(dto.getPlayer1());
                userService.fail(dto.getPlayer2());
                historyService.addHistory(dto.getPlayer1(), 1, 1, boards);
                historyService.addHistory(dto.getPlayer2(), 0, 1, boards);
                sendOneMsg(dto.getPlayer2(), "Fail!");
                sendOneMsg(dto.getPlayer1(), "Win!");
            }
            gameService.cleanRoom(((GameNoGameDto)eventMessage.getData()).getRoomId());
            logger.info("Player id:{} in room id:{} long time no game", ((GameNoGameDto)eventMessage.getData()).getUserId(), ((GameNoGameDto)eventMessage.getData()).getRoomId());
        }
    }
}
